#ifndef SYNTAX_H
#define SYNTAX_H

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;

#define TERMINAL_SYMBOL_NUM 32
#define NON_TERMINAL_SYMBOL_NUM 43

#define ACC -1
#define ERROR -2
#define INIT -3

extern const char *terminal_symbol[TERMINAL_SYMBOL_NUM];
extern const char *non_terminal_symbol[NON_TERMINAL_SYMBOL_NUM];

extern const char *start_symbol;
extern const char *expand_start_symbol;

struct item_info
{
    int point_pos; // 点的位置，0表示在最左边，依次类推
    int left;      // 产生式左侧的单词
    int right_num; // 产生式右侧单词的个数
    int right[10]; // 产生式右侧单词，只能访问到前right_num个，不能越界
};

struct item_family_edge
{
    int from;   // 起始状态
    int to;     // 目标状态
    int symbol; // 符号
    item_family_edge(int f, int t, int s)
        : from(f), to(t), symbol(s) {}
};

struct family_info
{
    bool is_expand; // 当前状态集是否扩充
    bool is_branch; // 当前状态集是否走完分支
    family_info(bool e, bool b)
        : is_expand(e), is_branch(b) {}
};

class Stack
{
private:
    int height;
    int stack[1000];
    bool is_symbol;

public:
    Stack(bool symbol) : height(0), is_symbol(symbol) {}
    void push(int a)
    {
        if (this->height >= 1000)
        {
            perror("Stack over range.\n");
        }
        stack[this->height++] = a;
        return;
    }
    void pop()
    {
        if (this->height > 0)
        {
            this->height--;
        }
        return;
    }
    int top()
    {
        if (this->height > 0 && this->height < 1000)
        {
            return stack[this->height - 1];
        }
        return -1;
    }
    int reduct(item_info item)
    {
        if(this->height < item.right_num)
        {
            return -1;
        }
        if (this->is_symbol)
        {
            for (int i = 0; i < item.right_num; i++)
            {
                if (item.right[i] != this->stack[this->height - (item.right_num - i)])
                {
                    return -1;
                }
            }
            this->height -= item.right_num;
            this->stack[this->height++] = item.left;
        }
        else
        {
            this->height -= item.right_num;
        } 
        return 0;
    }
    void print_all(ofstream &out)
    {
        if (this->is_symbol)
        {
            for (int i = 0; i < this->height; i++)
            {
                if (!this->stack[i])
                {
                    out << "# ";
                }
                else if (this->stack[i] <= TERMINAL_SYMBOL_NUM)
                {
                    out << terminal_symbol[this->stack[i] - 1] << " ";
                }
                else
                {
                    out << non_terminal_symbol[this->stack[i] - TERMINAL_SYMBOL_NUM - 1] << " ";
                }
            }
        }
        else
        {
            for (int i = 0; i < this->height; i++)
            {
                out << this->stack[i] << " ";
            }
        }
        return;
    }
};

// void get_production(production_info my_production[], item_info my_item[], int production_num, int item_num);
void init_state_table(int state_table[][TERMINAL_SYMBOL_NUM + NON_TERMINAL_SYMBOL_NUM + 1], int s_x);
void init_set(bool fisrt[][TERMINAL_SYMBOL_NUM + 1], bool follow[][TERMINAL_SYMBOL_NUM + 1]);
int get_FOLLOW(bool first[][TERMINAL_SYMBOL_NUM + 1], bool follow[][TERMINAL_SYMBOL_NUM + 1], item_info my_item[], int item_num);
int get_item(char *in_file, const char *start_symbol, const char *expand_start_symbol);
int get_item_family(char *in_file, int item_num, item_info my_item[], vector<vector<int>> &family_member, vector<item_family_edge> &my_edge);
int get_state_table(int state_table[][TERMINAL_SYMBOL_NUM + NON_TERMINAL_SYMBOL_NUM + 1], int family_num, item_info my_item[], int item_num, vector<vector<int>> family_member, vector<item_family_edge> my_edge, bool follow[][TERMINAL_SYMBOL_NUM + 1]);
int syntax_analyze(char *lex_file_path, int state_table[][TERMINAL_SYMBOL_NUM + NON_TERMINAL_SYMBOL_NUM + 1], int family_num, item_info my_item[], int acc_state);

#endif